#include "singleplayermodule.h"
#include "sceneobject.h"
#include "drunkscenemodel.h"
#include <QTime>
#include <QDebug>

SinglePlayerModule::SinglePlayerModule(int updateStateInterval,Noise *noise,int numberOfObjects,
int heightRange,int speedRange,int penaltyRange,int difficultyRange,QObject *parent){

    startedAt=new QTime;
    finishedAt=new QTime;

    yPosition=0;
    playerFinishingTime=-1;
    isStanding=true;

    qsrand((uint) QTime::currentTime().msec());

    float mapWidth=5;

    switch(heightRange){
    case SHORT:
        mapHeight=(qrand()%21+40);
        numberOfObjects/=2;
        break;
    case MEDIUM :
        mapHeight=(qrand()%31+60);
        break;
    case LONG :
        mapHeight=(qrand()%31+90);
        numberOfObjects*=1.5;
        break;
    case VERY_LONG:
        mapHeight=(qrand()%31+120);
        numberOfObjects*=2;
        break;
    }

    switch(speedRange){
    case SLOW :
        movementSpeed=0.8;
        break;
    case NORMAL :
        movementSpeed=1.6;
        break;
    case FAST :
        movementSpeed=2.4;
        break;
    }

    switch(penaltyRange){
    case SMALL :
        fallingDownPenalty=2000;
        break;
    case MODERATE :
        fallingDownPenalty=4000;
        break;
    case HIGH :
        fallingDownPenalty=6000;
        break;
    }

    float difficultyFactor=0.4;

    switch(difficultyRange){
    case SMALL :
        difficultyFactor=0.4;
        break;
    case MODERATE :
        difficultyFactor=0.6;
        break;
    case HIGH :
        difficultyFactor=0.8;
        break;
    case VERY_HIGH:
        difficultyFactor=1.0;
        break;
    }

    this->updateStateInterval=updateStateInterval;

    model=new DrunkSceneModel(updateStateInterval,mapWidth,mapHeight,noise,movementSpeed,fallingDownPenalty,parent);
    model->setNavigationDifficulty(difficultyFactor);

    float lastY=0;

    for(int i=0;i<numberOfObjects;i++){
        QString resourceId;
        float objectXPosition;
        float objectYPosition;

        objectXPosition=qrand()%((int)mapWidth);
        if(lastY/numberOfObjects < mapHeight/numberOfObjects)
            lastY+=0.6*mapHeight/numberOfObjects;

        objectYPosition=lastY+qrand()%((int)(mapHeight/numberOfObjects));
        lastY=objectYPosition;

        switch(qrand()%3){
        case 0:
            resourceId="banana";
            model->putObject(new SceneObject(2.0,1.5,1.0,1000,objectXPosition,objectYPosition,0.5,"banana"));
            break;
        case 1:
            resourceId="powerup";
            model->putObject(new SceneObject(0.6,0.8,1.3,5000,objectXPosition,objectYPosition,0.5,"powerup_energydrink"));
            break;
        case 2:default:
            resourceId="obstacle_crate_wood";
            model->putObject(new SceneObject(1.0,1.0,1.0,50,objectXPosition,objectYPosition,1.0,"obstacle_crate_wood"));
            break;
        }
    }

    connect(model,SIGNAL(reachedEndOfMap(int)),this,SLOT(playerFinishedAt(int)));
}

void SinglePlayerModule::simulateOpponentMovement(){
    if(yPosition==mapHeight)
        return;

    if(startedAt->isNull())
        *startedAt=QTime::currentTime();

    if(isStanding){
        yPosition += (updateStateInterval / 1000.0) * movementSpeed;

        if(yPosition>=mapHeight){
            yPosition=mapHeight;
            *finishedAt=QTime::currentTime();

            if(playerFinishingTime != -1)
                emit win(false,startedAt->msecsTo(*finishedAt));
            else
                emit win(true,startedAt->msecsTo(*finishedAt));

            emit opponentAt(yPosition);
            return;
        }

        if(qrand()>(RAND_MAX-RAND_MAX/50)){//very simplistic and there is no explanation for the calculation, anything goes
            intervalsToStand=fallingDownPenalty/updateStateInterval;
            isStanding=false;
        }
    }
    else{
        if(intervalsToStand>-1)
            intervalsToStand-=1;
        else
            isStanding=true;
    }
    emit opponentAt(yPosition);
}

DrunkSceneModel* SinglePlayerModule::getModel(){
    return model;
}

void SinglePlayerModule::playerFinishedAt(int msec){
    playerFinishingTime = msec;
}

SinglePlayerModule::~SinglePlayerModule(){
    if(finishedAt!=0)
        delete finishedAt;
    if(startedAt!=0)
        delete startedAt;
}
